﻿using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;

namespace NFox.Pycad
{
    public class Package : Module
    {

        public readonly string InitPyFileName = "__init__.py";

        public List<Module> Modules = new List<Module>();
        public List<Package> Packages = new List<Package>();

        public virtual DirectoryInfo Directory
        {
            get { return new DirectoryInfo(Path); }
        }

        public override int Level { get { return 0; } }

        public override FileInfo File
        {
            get { return Directory.GetFile(InitPyFileName); }
        }

        public override string FullName
        {
            get { return $"{Parent.FullName}.{Name}"; }
        }

        public override bool IsModule { get { return false; } }

        public override bool IsPackage { get { return true; } }

        public void GetFileNames(List<string> names)
        {
            names.Add($"'{File.FullName}'");
            foreach (var m in Modules)
                names.Add($"'{m.File.FullName}'");
            foreach (Package p in Packages)
                p.GetFileNames(names);
        }

        protected Package(string name) : base(name) { }

        protected Package(DirectoryInfo dir) : this(dir.Name)
        {
            foreach (var f in dir.GetFiles("*.py"))
            {
                if (f.Name != InitPyFileName)
                    Add(new Module(f.Name));
            }
            foreach (var d in dir.GetDirectories())
            {
                Add(new Package(d));
            }
        }

        #region Edit


        public override void CloseDocument()
        {
            base.CloseDocument();
            foreach (var m in Modules)
                m.CloseDocument();
            foreach (var p in Packages)
                p.CloseDocument();
        }

        public void Add(Module module)
        {
            module.Parent = this;
            if (module is Package)
                Packages.Add((Package)module);
            else
                Modules.Add(module);
            ModuleItemsChanged?.Invoke(this, new ModuleItemsEventArgs("Add", module));
        }

        public override void Remove()
        {
            CloseDocument();
            Parent.RemovePackage(this, true);
        }

        public void RemovePackage(Package package, bool delete)
        {
            if(delete) package.Directory.Delete(true);
            Packages.Remove(package);
            ModuleItemsChanged?.Invoke(this, new ModuleItemsEventArgs("Remove", package));
        }

        public void RemoveModule(Module module, bool delete)
        {
            if (delete) module.File.Delete();
            Modules.Remove(module);
            ModuleItemsChanged?.Invoke(this, new ModuleItemsEventArgs("Remove", module));
        }

        #endregion

        public Package GetPackage(string name)
        {
            foreach (Package p in Packages)
            {
                if (p.Name == name)
                    return p;
            }
            return null;
        }

        public Module GetModule(string name)
        {
            foreach (Module m in Modules)
            {
                if (m.Name == name)
                    return m;
            }
            return null;
        }

        public virtual Package CreateSubPackage(string name)
        {
            var dir = Directory.CreateSubdirectory(name);
            var file = new FileInfo(dir.FullName + "\\" + InitPyFileName);
            using (var fs = file.Create())
                fs.Close();
            var p = new Package(dir);
            Add(p);
            return p;
        }

        public Module CreateModule(string name, string content)
        {
            var file = new FileInfo(Directory.FullName + "\\" + name);
            using (var fs = file.Create())
            {
                using (StreamWriter sw = new StreamWriter(fs))
                {
                    sw.Write(content);
                }
            }
            var m = new Module(file.Name);
            Add(m);
            return m;
        }

        public bool Contains(string name)
        {
            foreach (var p in Packages)
            {
                if (p.Name.ToLower() == name.ToLower())
                    return true;
            }
            foreach (var m in Modules)
            {
                if (m.Name.ToLower() == name.ToLower())
                    return true;
            }
            return false;
        }

        public bool Validate(string name, bool ispackage)
        {
            var patt = @"^[a-zA-Z][a-zA-Z0-9]*";
            if (!ispackage)
                patt += @"\.py";
            patt += "$";
            name = name.Trim();
            if (string.IsNullOrEmpty(name))
                throw new System.Exception("名字不允许为空");
            if (Regex.IsMatch(name, patt))
            {
                if (Contains(name))
                    throw new System.Exception("名字重复");
                return true;
            }
            else
            {
                throw new System.Exception("验证错误");
            }
        }

        //要改
        public override bool CopyTo(Package parent)
        {
            Package package = parent.GetPackage(Name);
            if (package == null)
                package = parent.CreateSubPackage(Name);
            else
                package.CloseDocument();

            File.CopyTo(package.File.FullName, true);
            foreach (var m in Modules)
                m.CopyTo(package);
            foreach (var p in Packages)
                p.CopyTo(package);
            return false;
        }

        public override void Rename(string name)
        {
            Directory.MoveTo(Parent.Directory.FullName + "\\" + name);
            Parent.RemovePackage(this, false);
            Name = name;
            ModuleChanged?.Invoke(this, new ModuleEventArgs("Name"));
            Parent.Add(this);
        }

        public override string ToString()
        {
            return $"Package:({Path})";
        }

        public Module FindModuleByPath(string path)
        {

            if (Path == path)
                return this;

            foreach (var m in Modules)
            {
                if (m.Path == path)
                    return m;
            }

            foreach (var p in Packages)
            {
                var m = p.FindModuleByPath(path);
                if (m != null)
                    return m;
            }

            return null;

        }

    }
}
